﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.ComponentModel;
using System.Drawing.Text;

namespace ICSharpCode.WinFormsUI.Controls
{
    public class NTabControl : TabControl
    {
        #region Fields

        private int _space = 4;
        private int _radius = 8;       
        private int _tabstripcaptionLm = 0;

        private bool _onCreated = false;
        private bool _lineBrush = false;
        private bool _showClose = false;
        private bool _mouseInCloseRect = false;
        
        private Color _baseColor = Color.FromArgb(166, 222, 255);
        private Color _backColor = Color.FromArgb(234, 247, 254);
        private Color _borderColor = Color.FromArgb(23, 169, 254);
        private Color _arrowColor = Color.FromArgb(0, 79, 125);
        private Color _baseTabColor = Color.FromArgb(240, 240, 240);
        private Color _selectedTabColor = Color.FromArgb(255, 255, 255);        

        private UpDownButtonNativeWindow _upDownButtonNativeWindow;

        private const int CLOSE_SIZE = 16;
        private Rectangle CLOSE_RECT = new Rectangle();       
        private const string UpDownButtonClassName = "msctls_updown32";       
        private static readonly object EventPaintUpDownButton = new object();
        private Dictionary<string,Rectangle> CloseRectList = new Dictionary<string,Rectangle>(); 

        #endregion

        #region Constructors

        public NTabControl()
            : base()
        {
            SetStyles();
        }

        #endregion

        #region Events
        public event UpDownButtonPaintEventHandler PaintUpDownButton
        {
            add { base.Events.AddHandler(EventPaintUpDownButton, value); }
            remove { base.Events.RemoveHandler(EventPaintUpDownButton, value); }
        }
        #endregion

        #region Properties

        [DefaultValue(typeof(Color), "166, 222, 255")]
        public Color BaseColor
        {
            get { return _baseColor; }
            set
            {
                _baseColor = value;
                base.Invalidate(true);
            }
        }
        public bool ShowClose
        {
            get { return _showClose; }
            set { _showClose = value; }
        }

        [Browsable(true)]
        [EditorBrowsable(EditorBrowsableState.Always)]
        [DefaultValue(typeof(Color), "234, 247, 254")]
        public override Color BackColor
        {
            get { return _backColor; }
            set
            {
                _backColor = value;
                base.Invalidate(true);
            }
        }

        [DefaultValue(typeof(Color), "23, 169, 254")]
        public Color BorderColor
        {
            get { return _borderColor; }
            set
            {
                _borderColor = value;
                base.Invalidate(true);
            }
        }

        [DefaultValue(typeof(Color), "0, 95, 152")]
        public Color ArrowColor
        {
            get { return _arrowColor; }
            set
            {
                _arrowColor = value;
                base.Invalidate(true);
            }
        }

        [DefaultValue(typeof(Color), "255, 255, 255")]
        public Color SelectedColor
        {
            get { return _selectedTabColor; }
            set { _selectedTabColor = value; }
        }

        [DefaultValue(typeof(Color), "240, 240, 240")]
        public Color BaseTabColor
        {
            get { return _baseTabColor; }
            set { _baseTabColor = value; }
        }

        [DefaultValue(typeof(int), "8")]
        public int Radius
        {
            get { return _radius; }
            set { _radius = value; }
        }

        [DefaultValue(typeof(int), "0")]
        public int TabCaptionLm
        {
            get { return _tabstripcaptionLm; }
            set { _tabstripcaptionLm = value; }
        }

        internal IntPtr UpDownButtonHandle
        {
            get { return FindUpDownButton(); }
        }

        private bool _showWaitMessage=false;
        public bool ShowWaitMessage
        {
            get { return _showWaitMessage; }
            set
            {
                _showWaitMessage = value;
                this.Invalidate();
            }
        } 

        #endregion

        #region Protected Methods

        protected virtual void OnPaintUpDownButton(
            UpDownButtonPaintEventArgs e)
        {
            Graphics g = e.Graphics;
            Rectangle rect = e.ClipRectangle;

            Color upButtonBaseColor = _baseColor;
            Color upButtonBorderColor = _borderColor;
            Color upButtonArrowColor = _arrowColor;

            Color downButtonBaseColor = _baseColor;
            Color downButtonBorderColor = _borderColor;
            Color downButtonArrowColor = _arrowColor;

            Rectangle upButtonRect = rect;
            upButtonRect.X += 4;
            upButtonRect.Y += 4;
            upButtonRect.Width = rect.Width / 2 - 8;
            upButtonRect.Height -= 8;

            Rectangle downButtonRect = rect;
            downButtonRect.X = upButtonRect.Right + 2;
            downButtonRect.Y += 4;
            downButtonRect.Width = rect.Width / 2 - 8;
            downButtonRect.Height -= 8;

            if (Enabled)
            {
                if (e.MouseOver)
                {
                    if (e.MousePress)
                    {
                        if (e.MouseInUpButton)
                        {
                            upButtonBaseColor = GetColor(_baseColor, 0, -35, -24, -9);
                        }
                        else
                        {
                            downButtonBaseColor = GetColor(_baseColor, 0, -35, -24, -9);
                        }
                    }
                    else
                    {
                        if (e.MouseInUpButton)
                        {
                            upButtonBaseColor = GetColor(_baseColor, 0, 35, 24, 9);
                        }
                        else
                        {
                            downButtonBaseColor = GetColor(_baseColor, 0, 35, 24, 9);
                        }
                    }
                }
            }
            else
            {
                upButtonBaseColor = SystemColors.Control;
                upButtonBorderColor = SystemColors.ControlDark;
                upButtonArrowColor = SystemColors.ControlDark;

                downButtonBaseColor = SystemColors.Control;
                downButtonBorderColor = SystemColors.ControlDark;
                downButtonArrowColor = SystemColors.ControlDark;
            }

            g.SmoothingMode = SmoothingMode.AntiAlias;

            Color backColor = Enabled ? _backColor : SystemColors.Control;

            using (SolidBrush brush = new SolidBrush(_backColor))
            {
                rect.Inflate(1, 1);
                g.FillRectangle(brush, rect);
            }

            RenderButton(
                g,
                upButtonRect,
                upButtonBaseColor,
                upButtonBorderColor,
                upButtonArrowColor,
                ArrowDirection.Left);
            RenderButton(
                g,
                downButtonRect,
                downButtonBaseColor,
                downButtonBorderColor,
                downButtonArrowColor,
                ArrowDirection.Right);

            UpDownButtonPaintEventHandler handler =
                base.Events[EventPaintUpDownButton] as UpDownButtonPaintEventHandler;
            if (handler != null)
            {
                handler(this, e);
            }
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);

            this._mouseInCloseRect = false;            
            if (CLOSE_RECT.Contains(e.Location))
            {
                int _cusorIndex = GetMouseIndex(e.Location);
                if (SelectedIndex == _cusorIndex)                    
                {
                    this._mouseInCloseRect = true;
                    this.Cursor = Cursors.Hand;
                }
            }
            else
            {
                this.Cursor = Cursors.Default;
            }
            base.Invalidate();
        }

        protected override void OnMouseLeave(EventArgs e)
        {
            base.OnMouseLeave(e);
            base.Invalidate();
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            DrawTabContrl(e.Graphics);            
        }        

        protected override void OnHandleCreated(EventArgs e)
        {
            base.OnHandleCreated(e);
            if (UpDownButtonHandle != IntPtr.Zero)
            {
                if (_upDownButtonNativeWindow == null)
                {
                    _upDownButtonNativeWindow = new UpDownButtonNativeWindow(this);
                }
            }
        }

        protected override void OnCreateControl()
        {
            base.OnCreateControl();
            if (UpDownButtonHandle != IntPtr.Zero)
            {
                if (_upDownButtonNativeWindow == null)
                {
                    _upDownButtonNativeWindow = new UpDownButtonNativeWindow(this);
                }
            }
            if (!this._onCreated && this.ImageList != null && this._showClose)
            {
                this.ItemSize = new Size(this.ItemSize.Width + 12 + CLOSE_SIZE, this.ItemSize.Height);
                this._onCreated = true;
            }
        }

        protected override void OnHandleDestroyed(EventArgs e)
        {
            base.OnHandleDestroyed(e);
            if (_upDownButtonNativeWindow != null)
            {
                _upDownButtonNativeWindow.Dispose();
                _upDownButtonNativeWindow = null;
            }
        }

        protected override void OnControlAdded(ControlEventArgs e)
        {
            base.OnControlAdded(e);
            if (UpDownButtonHandle != IntPtr.Zero)
            {
                if (_upDownButtonNativeWindow == null)
                {
                    _upDownButtonNativeWindow = new UpDownButtonNativeWindow(this);
                }
            }
            //CloseRectList = new Dictionary<string, Rectangle>();
            //for (int index = 0; index < TabPages.Count; index++)
            //{
            //    Rectangle tabRect = GetTabRect(index);
            //    Rectangle closeRect = new Rectangle();
            //    switch (Alignment)
            //    {
            //        case TabAlignment.Top:
            //            closeRect.X = tabRect.X + tabRect.Width - (CLOSE_SIZE + 6);
            //            closeRect.Y = tabRect.Y + (this.ItemSize.Height - CLOSE_SIZE) / 2;
            //            break;
            //        case TabAlignment.Bottom:
            //            closeRect.X = tabRect.X + tabRect.Width - (CLOSE_SIZE + 6);
            //            closeRect.Y = tabRect.Y + tabRect.Height - (this.ItemSize.Height + CLOSE_SIZE) / 2;
            //            break;
            //        case TabAlignment.Left:
            //            closeRect.X = tabRect.X + tabRect.Width - (this.ItemSize.Height + CLOSE_SIZE) / 2;
            //            closeRect.Y = tabRect.Y + (this.ItemSize.Height - CLOSE_SIZE) / 2;
            //            break;
            //        case TabAlignment.Right:
            //            closeRect.X = tabRect.X + tabRect.Width - (this.ItemSize.Height + CLOSE_SIZE) / 2;
            //            closeRect.Y = tabRect.Y + (this.ItemSize.Height - CLOSE_SIZE) / 2;
            //            break;
            //    }
            //    closeRect.Width = CLOSE_SIZE;
            //    closeRect.Height = CLOSE_SIZE;
            //    if (!CloseRectList.ContainsKey("tab_" + index))
            //        CloseRectList.Add("tab_" + index, closeRect);
            //}
            this._mouseInCloseRect = false;
        }

        protected override void OnControlRemoved(ControlEventArgs e)
        {
            base.OnControlRemoved(e);

            //CloseRectList = new Dictionary<string, Rectangle>();

            //for (int index = 0; index < TabPages.Count; index++)
            //{
            //    Rectangle tabRect = GetTabRect(index);
            //    Rectangle closeRect = new Rectangle();
            //    switch (Alignment)
            //    {
            //        case TabAlignment.Top:
            //            closeRect.X = tabRect.X + tabRect.Width - (CLOSE_SIZE + 6);
            //            closeRect.Y = tabRect.Y + (this.ItemSize.Height - CLOSE_SIZE) / 2;
            //            break;
            //        case TabAlignment.Bottom:
            //            closeRect.X = tabRect.X + tabRect.Width - (CLOSE_SIZE + 6);
            //            closeRect.Y = tabRect.Y + tabRect.Height - (this.ItemSize.Height + CLOSE_SIZE) / 2;
            //            break;
            //        case TabAlignment.Left:
            //            closeRect.X = tabRect.X + tabRect.Width - (this.ItemSize.Height + CLOSE_SIZE) / 2;
            //            closeRect.Y = tabRect.Y + (this.ItemSize.Height - CLOSE_SIZE) / 2;
            //            break;
            //        case TabAlignment.Right:
            //            closeRect.X = tabRect.X + tabRect.Width - (this.ItemSize.Height + CLOSE_SIZE) / 2;
            //            closeRect.Y = tabRect.Y + (this.ItemSize.Height - CLOSE_SIZE) / 2;
            //            break;
            //    }
            //    closeRect.Width = CLOSE_SIZE;
            //    closeRect.Height = CLOSE_SIZE;
            //    if (!CloseRectList.ContainsKey("tab_" + index))
            //        CloseRectList.Add("tab_" + index, closeRect);
            //}
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
            if (UpDownButtonHandle != IntPtr.Zero)
            {
                if (_upDownButtonNativeWindow == null)
                {
                    _upDownButtonNativeWindow = new UpDownButtonNativeWindow(this);
                }
            }
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);
            if (this._showClose && _mouseInCloseRect && e.Button == MouseButtons.Left)
            {
                int index = SelectedIndex;
                int x = e.X, y = e.Y;
                Rectangle tabRect = GetTabRect(index);
                Rectangle closeRect = new Rectangle();
                switch (Alignment)
                {
                    case TabAlignment.Top:
                        closeRect.X = tabRect.X + tabRect.Width - (CLOSE_SIZE + 6);
                        closeRect.Y = tabRect.Y + (this.ItemSize.Height - CLOSE_SIZE) / 2;
                        break;
                    case TabAlignment.Bottom:
                        closeRect.X = tabRect.X + tabRect.Width - (CLOSE_SIZE + 6);
                        closeRect.Y = tabRect.Y + tabRect.Height - (this.ItemSize.Height + CLOSE_SIZE) / 2;
                        break;
                    case TabAlignment.Left:
                        closeRect.X = tabRect.X + tabRect.Width - (this.ItemSize.Height + CLOSE_SIZE) / 2;
                        closeRect.Y = tabRect.Y + (this.ItemSize.Height - CLOSE_SIZE) / 2;
                        break;
                    case TabAlignment.Right:
                        closeRect.X = tabRect.X + tabRect.Width - (this.ItemSize.Height + CLOSE_SIZE) / 2;
                        closeRect.Y = tabRect.Y + (this.ItemSize.Height - CLOSE_SIZE) / 2;
                        break;
                }
                closeRect.Width = CLOSE_SIZE;
                closeRect.Height = CLOSE_SIZE;
                this.CLOSE_RECT = closeRect;
                if (closeRect.Contains(e.Location))
                {
                    TabPages.Remove(SelectedTab);
                    if (index > 1)
                        SelectedIndex = index - 1;
                }               
            }
        }

        protected override void OnDrawItem(DrawItemEventArgs e)
        {
            base.OnDrawItem(e);
        }

        #endregion

        #region Help Methods

        private IntPtr FindUpDownButton()
        {
            return NativeMethods.FindWindowEx(
                base.Handle,
                IntPtr.Zero,
                UpDownButtonClassName,
                null);
        }

        private void SetStyles()
        {
            this.SetStyle(
                ControlStyles.UserPaint |
                ControlStyles.OptimizedDoubleBuffer |
                ControlStyles.AllPaintingInWmPaint |
                ControlStyles.ResizeRedraw |
                ControlStyles.SupportsTransparentBackColor, true);
            this.UpdateStyles();
        }

        private void DrawTabContrl(Graphics g)
        {
            g.SmoothingMode = SmoothingMode.AntiAlias;
            g.InterpolationMode = InterpolationMode.HighQualityBilinear;
            g.TextRenderingHint = TextRenderingHint.AntiAlias;
            DrawDrawBackgroundAndHeader(g);
            DrawWaitMessageBox(g);
            DrawTabPages(g);
            DrawBorder(g);
        }

        private void DrawWaitMessageBox(Graphics g)
        {
            if (_showWaitMessage) //&& this.TabCount <= 0
            {
                Rectangle box_rect = new Rectangle(0, 0, 200, 40);
                Rectangle clt_rect = this.ClientRectangle;
                clt_rect.Inflate(-4, -4);
                if (clt_rect.Width > box_rect.Width && clt_rect.Height > box_rect.Height)
                {
                    box_rect.X = clt_rect.X + (clt_rect.Width - box_rect.Width) / 2;
                    box_rect.Y = clt_rect.Y + (clt_rect.Height - box_rect.Height) / 2;

                    GraphicsPath path = CommonHelper.CreateRoundedRectanglePath(box_rect, _radius);

                    using (Brush bru = new SolidBrush(SystemColors.AppWorkspace))
                    {
                        g.FillRectangle(bru, clt_rect);
                    }

                    using (Brush bru = new SolidBrush(SystemColors.Control))
                    {
                        g.FillPath(bru, path);                       
                    }

                    using (Brush bru = new SolidBrush(SystemColors.ControlDarkDark))
                    {
                        g.DrawPath(new Pen(bru, 1.0f), path);
                    }

                    using (Brush bru = new SolidBrush(SystemColors.MenuText))
                    {
                        StringFormat sf = new StringFormat();
                        sf.LineAlignment = StringAlignment.Center;
                        sf.Alignment = StringAlignment.Center;
                        g.DrawString("系统正在处理中...", this.Font, bru, box_rect, sf);
                    }

                    path.Dispose();
                    
                }
            }
        }

        private void DrawDrawBackgroundAndHeader(Graphics g)
        {
            int x = 0;
            int y = 0;
            int width = 0;
            int height = 0;

            switch (Alignment)
            {
                case TabAlignment.Top:
                    x = 0;
                    y = 0;
                    width = ClientRectangle.Width;
                    height = ClientRectangle.Height - DisplayRectangle.Height;
                    break;
                case TabAlignment.Bottom:
                    x = 0;
                    y = DisplayRectangle.Height;
                    width = ClientRectangle.Width;
                    height = ClientRectangle.Height - DisplayRectangle.Height;
                    break;
                case TabAlignment.Left:
                    x = 0;
                    y = 0;
                    width = ClientRectangle.Width - DisplayRectangle.Width;
                    height = ClientRectangle.Height;
                    break;
                case TabAlignment.Right:
                    x = DisplayRectangle.Width;
                    y = 0;
                    width = ClientRectangle.Width - DisplayRectangle.Width;
                    height = ClientRectangle.Height;
                    break;
            }

            Rectangle headerRect = new Rectangle(x, y, width, height);
            Color backColor = Enabled ? _backColor : SystemColors.Control;
            using (SolidBrush brush = new SolidBrush(backColor))
            {
                g.FillRectangle(brush, ClientRectangle);
                g.FillRectangle(brush, headerRect);
            }
        }
       
        private void DrawTabPages(Graphics g)
        {
            Rectangle tabRect;
            Point cusorPoint = PointToClient(MousePosition);
            bool hover;
            bool selected;
            bool hasSetClip = false;
            bool alignHorizontal =
                (Alignment == TabAlignment.Top ||
                Alignment == TabAlignment.Bottom);
            LinearGradientMode mode = alignHorizontal ?
                LinearGradientMode.Vertical : LinearGradientMode.Horizontal;

            if (alignHorizontal)
            {
                IntPtr upDownButtonHandle = UpDownButtonHandle;
                bool hasUpDown = upDownButtonHandle != IntPtr.Zero;
                if (hasUpDown)
                {
                    if (NativeMethods.IsWindowVisible(upDownButtonHandle))
                    {
                        NativeMethods.RECT upDownButtonRect = new NativeMethods.RECT();
                        NativeMethods.GetWindowRect(
                            upDownButtonHandle, ref upDownButtonRect);
                        Rectangle upDownRect = Rectangle.FromLTRB(
                            upDownButtonRect.Left,
                            upDownButtonRect.Top,
                            upDownButtonRect.Right,
                            upDownButtonRect.Bottom);
                        upDownRect = RectangleToClient(upDownRect);

                        switch (Alignment)
                        {
                            case TabAlignment.Top:
                                upDownRect.Y = 0;
                                break;
                            case TabAlignment.Bottom:
                                upDownRect.Y =
                                    ClientRectangle.Height - DisplayRectangle.Height;
                                break;
                        }
                        upDownRect.Height = ClientRectangle.Height;
                        g.SetClip(upDownRect, CombineMode.Exclude);
                        hasSetClip = true;
                    }
                }
            }

            for (int index = 0; index < base.TabCount; index++)
            {
                TabPage page = TabPages[index];
               
                tabRect = GetTabRect(index);              

                hover = tabRect.Contains(cusorPoint);
                selected = SelectedIndex == index;

                Color baseColor = _baseColor;
                Color tabColor = _baseTabColor;
                Color borderColor = _borderColor;               

                if (selected)
                {
                    tabColor = _selectedTabColor;
                    if (hover)
                    {
                        tabColor = GetColor(_baseColor, 100, 35, 24, 9);
                    }
                }
                else if (hover)
                {
                    tabColor = GetColor(_baseColor, 0, 35, 24, 9);
                }

                RenderTabBackgroundInternal(
                    g,
                    tabRect,
                    tabColor,
                    borderColor,                    
                    .45F,
                    mode);

                Size imgsize;
                bool hasImage = DrawTabImage(g, page, tabRect, out imgsize);
                DrawtabText(g, page, tabRect, hasImage, imgsize);

                if (_showClose && (index == SelectedIndex))
                {
                    Rectangle closeRect = new Rectangle();
                    switch (Alignment)
                    {
                        case TabAlignment.Top:
                            closeRect.X = tabRect.X + tabRect.Width - (CLOSE_SIZE + 6) - _radius / 2;
                            closeRect.Y = tabRect.Y + (this.ItemSize.Height - CLOSE_SIZE) / 2;
                            break;
                        case TabAlignment.Bottom:
                            closeRect.X = tabRect.X + tabRect.Width - (CLOSE_SIZE + 6) - _radius / 2;
                            closeRect.Y = tabRect.Y + tabRect.Height - (this.ItemSize.Height + CLOSE_SIZE) / 2;
                            break;
                        case TabAlignment.Left:
                            closeRect.X = tabRect.X + tabRect.Width - (this.ItemSize.Height + CLOSE_SIZE) / 2;
                            closeRect.Y = tabRect.Y + (this.ItemSize.Height - CLOSE_SIZE) / 2;
                            break;
                        case TabAlignment.Right:
                            closeRect.X = tabRect.X + (CLOSE_SIZE + _radius) / 2;
                            closeRect.Y = tabRect.Y + tabRect.Height - ((this.ItemSize.Height + CLOSE_SIZE) / 2);
                            break;
                    }
                    closeRect.Width = CLOSE_SIZE;
                    closeRect.Height = CLOSE_SIZE;

                    this.CLOSE_RECT = closeRect;

                    ////再画一个矩形框
                    //using (Pen p = new Pen(Color.Red, 1))
                    //{
                    //    //g.DrawRectangle(p, closeRect);
                    //    g.DrawEllipse(p, closeRect);
                    //}

                    if (selected && _mouseInCloseRect)
                    {
                        using (Brush b = new SolidBrush(SystemColors.ControlDark))
                        {
                            g.FillEllipse(b, closeRect);
                        }
                    }

                    //画关闭符号
                    using (Pen p = new Pen(Color.Red, 2))
                    {
                        //画"\"线
                        Point p1 = new Point(closeRect.X + _space, closeRect.Y + _space);
                        Point p2 = new Point(closeRect.X + closeRect.Width - _space, closeRect.Y + closeRect.Height - _space);
                        g.DrawLine(p, p1, p2);

                        //画"/"线
                        Point p3 = new Point(closeRect.X + _space, closeRect.Y + closeRect.Height - _space);
                        Point p4 = new Point(closeRect.X + closeRect.Width - _space, closeRect.Y + _space);
                        g.DrawLine(p, p3, p4);
                    }
                }

            }

            if (hasSetClip)
            {
                g.ResetClip();
            }
        }

        private void DrawtabText(
            Graphics g, TabPage page, Rectangle tabRect, bool hasImage,Size imgSize)
        {
            Rectangle textRect = new Rectangle(tabRect.X, tabRect.Y, tabRect.Width, tabRect.Height);
            RectangleF newTextRect;
            StringFormat sf;

            switch (Alignment)
            {
                case TabAlignment.Top:
                case TabAlignment.Bottom:
                    if (hasImage)
                    {
                        textRect.X = textRect.X + _radius / 2 + imgSize.Width + 16;//+ textRect.Height - 2   
                        if (_showClose)
                        {
                            textRect.Width = textRect.Width - _radius - imgSize.Width - 16 - CLOSE_SIZE - 6;
                        }
                        else
                        {
                            textRect.Width = textRect.Width - _radius - imgSize.Width - 16 - 6;
                        }
                    }
                    else
                    {
                        textRect.X = textRect.X + _radius / 2 + 6;
                        if (_showClose)
                        {
                            textRect.Width = textRect.Width - _radius - CLOSE_SIZE - 12;
                        }
                        else
                        {
                            textRect.Width = textRect.Width - _radius - 6;
                        }                       
                    }
                    TextRenderer.DrawText(
                        g,
                        page.Text,
                        page.Font,
                        textRect,
                        page.ForeColor,
                        TextFormatFlags.Left 
                        | TextFormatFlags.VerticalCenter);
                    break;
                case TabAlignment.Left:
                    if (hasImage)
                    {
                        textRect.Height = tabRect.Height - tabRect.Width + 2;
                    }
                    g.TranslateTransform(textRect.X, textRect.Bottom);
                    g.RotateTransform(270F);
                    sf = new StringFormat(StringFormatFlags.NoWrap);
                    sf.Alignment = StringAlignment.Center;
                    sf.LineAlignment = StringAlignment.Center;
                    sf.Trimming = StringTrimming.Character;
                    newTextRect = textRect;
                    newTextRect.X = -CLOSE_SIZE;
                    newTextRect.Y = 0;
                    newTextRect.Width = textRect.Height;
                    newTextRect.Height = textRect.Width;
                    using (Brush brush = new SolidBrush(page.ForeColor))
                    {
                        g.DrawString(
                            page.Text,
                            page.Font,
                            brush,
                            newTextRect,
                            sf);
                    }
                    g.ResetTransform();
                    break;
                case TabAlignment.Right:
                    if (hasImage)
                    {
                        textRect.Y = tabRect.Y + _radius / 2 + tabRect.Width - 2;
                        textRect.Height = tabRect.Height - _radius - tabRect.Width;
                    }
                    g.TranslateTransform(textRect.Right, textRect.Y);
                    g.RotateTransform(90F);
                    sf = new StringFormat(StringFormatFlags.NoWrap);
                    sf.Alignment = StringAlignment.Center;
                    sf.LineAlignment = StringAlignment.Center;
                    sf.Trimming = StringTrimming.Character;
                    newTextRect = textRect;
                    newTextRect.X = -CLOSE_SIZE;
                    newTextRect.Y = 0;
                    newTextRect.Width = textRect.Height;
                    newTextRect.Height = textRect.Width;
                    using (Brush brush = new SolidBrush(page.ForeColor))
                    {
                        g.DrawString(
                            page.Text,
                            page.Font,
                            brush,
                            newTextRect,
                            sf);
                    }
                    g.ResetTransform();
                    break;
            }
        }

        private bool DrawTabImage(
            Graphics g, TabPage page, Rectangle tabRect, out Size imageSize)
        {
            bool hasImage = false;
            imageSize = new Size(16, 16);
            if (ImageList != null)
            {
                Image image = null;
                if (ImageList != null)
                {
                    if (page.ImageIndex != -1)
                    {
                        image = ImageList.Images[page.ImageIndex];
                    }
                    else if (page.ImageKey != null)
                    {
                        image = ImageList.Images[page.ImageKey];
                    }
                }

                if (image != null)
                {
                    hasImage = true;
                    imageSize = new Size(image.Width, image.Height);
                    Rectangle destRect = Rectangle.Empty;
                    Rectangle srcRect = new Rectangle(Point.Empty, image.Size);
                    switch (Alignment)
                    {
                        case TabAlignment.Top:
                        case TabAlignment.Bottom:
                            destRect = new Rectangle(
                                 tabRect.X + _radius / 2 + 8,
                                 tabRect.Y + (tabRect.Height - imageSize.Height)/2,
                                 imageSize.Width,
                                 imageSize.Height);
                            break;
                        case TabAlignment.Left:
                            destRect = new Rectangle(
                                tabRect.X + (tabRect.Width - imageSize.Width) / 2,
                                tabRect.Y + tabRect.Height - (_radius / 2 + (tabRect.Height - imageSize.Width) / 2) + CLOSE_SIZE,
                                imageSize.Width,
                                imageSize.Height);
                            break;
                        case TabAlignment.Right:
                            destRect = new Rectangle(
                                tabRect.X + (tabRect.Width - imageSize.Width) / 2,
                                tabRect.Y + _radius / 2 + 8,
                                imageSize.Width,
                                imageSize.Height);
                            break;
                    }

                    g.DrawImage(
                        image,
                        destRect,
                        srcRect,
                        GraphicsUnit.Pixel);
                }
            }
            return hasImage;
        }


        private void DrawBorder(Graphics g)
        {
            if (SelectedIndex != -1)
            {
                Rectangle tabRect = GetTabRect(SelectedIndex);
                //Rectangle clipRect = ClientRectangle;
                //clipRect.Inflate(-1, 0);
                //clipRect.Offset(-1, 0);  
                Rectangle clipRect = new Rectangle(ClientRectangle.X, ClientRectangle.Y, ClientRectangle.Width - 1, ClientRectangle.Height);
                Point[] points = new Point[6];

                IntPtr upDownButtonHandle = UpDownButtonHandle;
                bool hasUpDown = upDownButtonHandle != IntPtr.Zero;
                if (hasUpDown)
                {
                    if (NativeMethods.IsWindowVisible(upDownButtonHandle))
                    {
                        NativeMethods.RECT upDownButtonRect = new NativeMethods.RECT();
                        NativeMethods.GetWindowRect(
                            upDownButtonHandle,
                            ref upDownButtonRect);
                        Rectangle upDownRect = Rectangle.FromLTRB(
                            upDownButtonRect.Left,
                            upDownButtonRect.Top,
                            upDownButtonRect.Right,
                            upDownButtonRect.Bottom);
                        upDownRect = RectangleToClient(upDownRect);

                        tabRect.X = tabRect.X > upDownRect.X ?
                            upDownRect.X : tabRect.X;
                        tabRect.Width = tabRect.Right > upDownRect.X ?
                            upDownRect.X - tabRect.X : tabRect.Width;
                    }
                }

                switch (Alignment)
                {
                    case TabAlignment.Top:
                        points[0] = new Point(
                            tabRect.X,
                            tabRect.Bottom);
                        points[1] = new Point(
                            clipRect.X,
                            tabRect.Bottom);
                        points[2] = new Point(
                            clipRect.X,
                            clipRect.Bottom - 1);
                        points[3] = new Point(
                            clipRect.Right - 1,
                            clipRect.Bottom - 1);
                        points[4] = new Point(
                            clipRect.Right - 1,
                            tabRect.Bottom);
                        points[5] = new Point(
                            tabRect.Right,
                            tabRect.Bottom);
                        break;
                    case TabAlignment.Bottom:
                        points[0] = new Point(
                            tabRect.X,
                            tabRect.Y);
                        points[1] = new Point(
                            clipRect.X,
                            tabRect.Y);
                        points[2] = new Point(
                            clipRect.X,
                            clipRect.Y);
                        points[3] = new Point(
                            clipRect.Right - 1,
                            clipRect.Y);
                        points[4] = new Point(
                            clipRect.Right - 1,
                            tabRect.Y);
                        points[5] = new Point(
                            tabRect.Right,
                            tabRect.Y);
                        break;
                    case TabAlignment.Left:
                        points[0] = new Point(
                            tabRect.Right,
                            tabRect.Y);
                        points[1] = new Point(
                            tabRect.Right,
                            clipRect.Y);
                        points[2] = new Point(
                            clipRect.Right - 1,
                            clipRect.Y);
                        points[3] = new Point(
                            clipRect.Right - 1,
                            clipRect.Bottom - 1);
                        points[4] = new Point(
                            tabRect.Right,
                            clipRect.Bottom - 1);
                        points[5] = new Point(
                            tabRect.Right,
                            tabRect.Bottom);
                        break;
                    case TabAlignment.Right:
                        points[0] = new Point(
                            tabRect.X,
                            tabRect.Y);                        
                        points[1] = new Point(
                            tabRect.X,
                            clipRect.Y);
                        points[2] = new Point(
                            clipRect.X,
                            clipRect.Y);
                        points[3] = new Point(
                            clipRect.X,
                            clipRect.Bottom - 1);
                        points[4] = new Point(
                            tabRect.X,
                            clipRect.Bottom - 1);
                        points[5] = new Point(
                            tabRect.X,
                            tabRect.Bottom);
                        break;
                }
                using (Pen pen = new Pen(_borderColor))
                {
                    g.DrawLines(pen, points);
                }
            }
        }

        internal void RenderArrowInternal(
             Graphics g,
             Rectangle dropDownRect,
             ArrowDirection direction,
             Brush brush)
        {
            Point point = new Point(
                dropDownRect.Left + (dropDownRect.Width / 2),
                dropDownRect.Top + (dropDownRect.Height / 2));
            Point[] points = null;
            switch (direction)
            {
                case ArrowDirection.Left:
                    points = new Point[] { 
                        new Point(point.X + 1, point.Y - 4), 
                        new Point(point.X + 1, point.Y + 4), 
                        new Point(point.X - 2, point.Y) };
                    break;

                case ArrowDirection.Up:
                    points = new Point[] { 
                        new Point(point.X - 3, point.Y + 1), 
                        new Point(point.X + 3, point.Y + 1), 
                        new Point(point.X, point.Y - 1) };
                    break;

                case ArrowDirection.Right:
                    points = new Point[] {
                        new Point(point.X - 1, point.Y - 4), 
                        new Point(point.X - 1, point.Y + 4), 
                        new Point(point.X + 2, point.Y) };
                    break;

                default:
                    points = new Point[] {
                        new Point(point.X - 3, point.Y - 1), 
                        new Point(point.X + 3, point.Y - 1), 
                        new Point(point.X, point.Y + 1) };
                    break;
            }
            g.FillPolygon(brush, points);
        }

        internal void RenderButton(
            Graphics g,
            Rectangle rect,
            Color baseColor,
            Color borderColor,
            Color arrowColor,
            ArrowDirection direction)
        {
            RenderBackgroundInternal(
                g,
                rect,
                baseColor,
                borderColor,
                0.45f,
                true,
                LinearGradientMode.Vertical);
            using (SolidBrush brush = new SolidBrush(arrowColor))
            {
                RenderArrowInternal(
                    g,
                    rect,
                    direction,
                    brush);
            }
        }

        internal void RenderBackgroundInternal(
          Graphics g,
          Rectangle rect,
          Color baseColor,
          Color borderColor,
          float basePosition,
          bool drawBorder,
          LinearGradientMode mode)
        {
            using (LinearGradientBrush brush = new LinearGradientBrush(
               rect, Color.Transparent, Color.Transparent, mode))
            {
                Color[] colors = new Color[4];
                colors[0] = GetColor(baseColor, 0, 35, 24, 9);
                colors[1] = GetColor(baseColor, 0, 13, 8, 3);
                colors[2] = baseColor;
                colors[3] = GetColor(baseColor, 0, 68, 69, 54);

                ColorBlend blend = new ColorBlend();
                blend.Positions =
                    new float[] { 0.0f, basePosition, basePosition + 0.05f, 1.0f };
                blend.Colors = colors;
                brush.InterpolationColors = blend;
                g.FillRectangle(brush, rect);
            }
            if (baseColor.A > 80)
            {
                Rectangle rectTop = rect;
                if (mode == LinearGradientMode.Vertical)
                {
                    rectTop.Height = (int)(rectTop.Height * basePosition);
                }
                else
                {
                    rectTop.Width = (int)(rect.Width * basePosition);
                }
                using (SolidBrush brushAlpha =
                    new SolidBrush(Color.FromArgb(80, 255, 255, 255)))
                {
                    g.FillRectangle(brushAlpha, rectTop);
                }
            }

            if (drawBorder)
            {
                using (Pen pen = new Pen(borderColor))
                {
                    g.DrawRectangle(pen, rect);
                }
            }
        }

        internal void RenderTabBackgroundInternal(
          Graphics g,
          Rectangle rect,
          Color baseColor,
          Color borderColor,         
          float basePosition,
          LinearGradientMode mode)
        {
            using (GraphicsPath path = CreateTabPath(rect))
            {
                if (_lineBrush)
                {
                    using (LinearGradientBrush brush = new LinearGradientBrush(
                       rect, Color.Transparent, Color.Transparent, mode))
                    {
                        Color[] colors = new Color[4];
                        colors[0] = GetColor(baseColor, 0, 35, 24, 9);
                        colors[1] = GetColor(baseColor, 0, 13, 8, 3);
                        colors[2] = baseColor;
                        colors[3] = GetColor(baseColor, 0, 68, 69, 54);

                        ColorBlend blend = new ColorBlend();
                        blend.Positions =
                            new float[] { 0.0f, basePosition, basePosition + 0.05f, 1.0f };
                        blend.Colors = colors;
                        brush.InterpolationColors = blend;
                        g.FillPath(brush, path);
                    }
                }
                else
                {
                    Brush brush = new SolidBrush(baseColor);                   
                    g.FillPath(brush, path);
                }                 

                rect.Inflate(-1, -1);
                using (GraphicsPath path1 = CreateTabPath(rect))
                {
                    using (Pen pen = new Pen(Color.FromArgb(255, 255, 255)))
                    {
                        if (Multiline)
                        {
                            g.DrawPath(pen, path1);
                        }
                        else
                        {
                            g.DrawLines(pen, path1.PathPoints);
                        }
                    }
                }

                using (Pen pen = new Pen(borderColor,1.0f))
                {
                    if (Multiline)
                    {
                        g.DrawPath(pen, path);
                    }
                    {
                        g.DrawLines(pen, path.PathPoints);
                    }
                }
            }
        }

        private GraphicsPath CreateTabPath(Rectangle rect)
        {
            GraphicsPath path = new GraphicsPath();
            switch (Alignment)
            {
                case TabAlignment.Top:
                    rect.X++;
                    rect.Width -= 2;
                    path.AddLine(
                        rect.X,
                        rect.Bottom,
                        rect.X,
                        rect.Y + _radius / 2);
                    path.AddArc(
                        rect.X,
                        rect.Y,
                        _radius,
                        _radius,
                        180F,
                        90F);
                    path.AddArc(
                        rect.Right - _radius,
                        rect.Y,
                        _radius,
                        _radius,
                        270F,
                        90F);
                    path.AddLine(
                        rect.Right,
                        rect.Y + _radius / 2,
                        rect.Right,
                        rect.Bottom);
                    break;
                case TabAlignment.Bottom:
                    rect.X++;
                    rect.Width -= 2;
                    path.AddLine(
                        rect.X,
                        rect.Y,
                        rect.X,
                        rect.Bottom - _radius / 2);
                    path.AddArc(
                        rect.X,
                        rect.Bottom - _radius,
                        _radius,
                        _radius,
                        180,
                        -90);
                    path.AddArc(
                        rect.Right - _radius,
                        rect.Bottom - _radius,
                        _radius,
                        _radius,
                        90,
                        -90);
                    path.AddLine(
                        rect.Right,
                        rect.Bottom - _radius / 2,
                        rect.Right,
                        rect.Y);

                    break;
                case TabAlignment.Left:
                    rect.Y++;
                    rect.Height -= 2;
                    path.AddLine(
                        rect.Right,
                        rect.Y,
                        rect.X + _radius / 2,
                        rect.Y);
                    path.AddArc(
                        rect.X,
                        rect.Y,
                        _radius,
                        _radius,
                        270F,
                        -90F);
                    path.AddArc(
                        rect.X,
                        rect.Bottom - _radius,
                        _radius,
                        _radius,
                        180F,
                        -90F);
                    path.AddLine(
                        rect.X + _radius / 2,
                        rect.Bottom,
                        rect.Right,
                        rect.Bottom);
                    break;
                case TabAlignment.Right:
                    rect.Y++;
                    rect.Height -= 2;
                    path.AddLine(
                        rect.X,
                        rect.Y,
                        rect.Right - _radius / 2,
                        rect.Y);
                    path.AddArc(
                        rect.Right - _radius,
                        rect.Y,
                        _radius,
                        _radius,
                        270F,
                        90F);
                    path.AddArc(
                        rect.Right - _radius,
                        rect.Bottom - _radius,
                        _radius,
                        _radius,
                        0F,
                        90F);
                    path.AddLine(
                        rect.Right - _radius / 2,
                        rect.Bottom,
                        rect.X,
                        rect.Bottom);
                    break;
            }
            path.CloseFigure();
            return path;
        }

        private Color GetColor(Color colorBase, int a, int r, int g, int b)
        {
            int a0 = colorBase.A;
            int r0 = colorBase.R;
            int g0 = colorBase.G;
            int b0 = colorBase.B;

            if (a + a0 > 255) { a = 255; } else { a = Math.Max(a + a0, 0); }
            if (r + r0 > 255) { r = 255; } else { r = Math.Max(r + r0, 0); }
            if (g + g0 > 255) { g = 255; } else { g = Math.Max(g + g0, 0); }
            if (b + b0 > 255) { b = 255; } else { b = Math.Max(b + b0, 0); }

            return Color.FromArgb(a, r, g, b);
        }

        private int GetMouseIndex(Point cusorPt)
        {
            int _currrentIndex=0;
            for (int index = 0; index < this.TabPages.Count; index++)
            {
                Rectangle rect = GetTabRect(index);
                if (rect.Contains(cusorPt))
                {
                    _currrentIndex = index;
                    break;
                }
            }
            return _currrentIndex;
        }

        public new Rectangle GetTabRect(int SelectedIndex)
        {
            Rectangle rect = base.GetTabRect(SelectedIndex);
            rect.Offset(_tabstripcaptionLm, 0);            
            return rect;
        }

        #endregion

        #region UpDownButtonNativeWindow

        private class UpDownButtonNativeWindow : NativeWindow, IDisposable
        {
            private NTabControl _owner;
            private bool _bPainting;

            public UpDownButtonNativeWindow(NTabControl owner)
                : base()
            {
                _owner = owner;
                base.AssignHandle(owner.UpDownButtonHandle);
            }

            private bool LeftKeyPressed()
            {
                if (SystemInformation.MouseButtonsSwapped)
                {
                    return (NativeMethods.GetKeyState(NativeMethods.VK_RBUTTON) < 0);
                }
                else
                {
                    return (NativeMethods.GetKeyState(NativeMethods.VK_LBUTTON) < 0);
                }
            }

            private void DrawUpDownButton()
            {
                bool mouseOver = false;
                bool mousePress = LeftKeyPressed();
                bool mouseInUpButton = false;

                NativeMethods.RECT rect = new NativeMethods.RECT();

                NativeMethods.GetClientRect(base.Handle, ref rect);

                Rectangle clipRect = Rectangle.FromLTRB(
                    rect.Top, rect.Left, rect.Right, rect.Bottom);

                Point cursorPoint = new Point();
                NativeMethods.GetCursorPos(ref cursorPoint);
                NativeMethods.GetWindowRect(base.Handle, ref rect);

                mouseOver = NativeMethods.PtInRect(ref rect, cursorPoint);

                cursorPoint.X -= rect.Left;
                cursorPoint.Y -= rect.Top;

                mouseInUpButton = cursorPoint.X < clipRect.Width / 2;

                using (Graphics g = Graphics.FromHwnd(base.Handle))
                {
                    UpDownButtonPaintEventArgs e =
                        new UpDownButtonPaintEventArgs(
                        g,
                        clipRect,
                        mouseOver,
                        mousePress,
                        mouseInUpButton);
                    _owner.OnPaintUpDownButton(e);
                }
            }

            protected override void WndProc(ref Message m)
            {
                switch (m.Msg)
                {
                    case NativeMethods.WM_PAINT:
                        if (!_bPainting)
                        {
                            NativeMethods.PAINTSTRUCT ps =
                                new NativeMethods.PAINTSTRUCT();
                            _bPainting = true;
                            NativeMethods.BeginPaint(m.HWnd, ref ps);
                            DrawUpDownButton();
                            NativeMethods.EndPaint(m.HWnd, ref ps);
                            _bPainting = false;
                            m.Result = NativeMethods.TRUE;
                        }
                        else
                        {
                            base.WndProc(ref m);
                        }
                        break;
                    default:
                        base.WndProc(ref m);
                        break;
                }
            }

            #region IDisposable 成员

            public void Dispose()
            {
                _owner = null;
                base.ReleaseHandle();
            }

            #endregion
        }

        #endregion

    }
}
